package middleware;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;

import logging.Logging;

// Abstract class that implements the common logics of sharding and full replications,
// i.e. functions and values that are also used by the inheriting classes.
// runs as own thread.
public abstract class AbstractDatabaseLogic extends Thread {

	/**
	 * Set of database handlers that represent a connection and statement string.
	 * Each one consists of a permanent (never-changing) connection to a server.
	 */
	protected ArrayList<DatabaseHandler> dbHandler = new ArrayList<DatabaseHandler>();
	/**
	 * @uml.property  name="queue"
	 * @uml.associationEnd  
	 */
	protected Queue queue;
	
	/**
	 * Initializes class, creating an array of DatabaseHandler - one for each DB.
	 * These are immediately run as own threads.
	 * @param conns array of connections
	 * @param q queue
	 */
	public AbstractDatabaseLogic(ArrayList<Connection> conns, Queue q) {
		
		for (int i = 0; i < conns.size(); i++) {
			dbHandler.add(new DatabaseHandler(conns.get(i)));
			dbHandler.get(i).start();
		}
		
		queue = q;
	}
	
	/**
	 * Fetches ClientHandler from queue.
	 * @return ClientHandler. 
	 */
	protected ClientHandler fetchStatement() {
		return queue.remove();
	}
	
	/**
	 * Checks whether a ClientHandler contains an update statement.
	 * @param ch Client Handler
	 * @return 0 if update, 1 if query, 2 if preparedStatement struct
	 */
	protected int getType(ClientHandler ch) {
		int type;
		
		// parse string to check whether it is update or query
		String testString = ch.getQuery().toLowerCase().trim();
		if (testString.contains("=")) {
			type = 2;
		} else if (testString.contains("|")) {
			type = 0;
		} else {
			type = 1;
		}
		
		return type;
	}
	
	/**
	 * Processes a statement and sends to databases that are to perform the statement.
	 * Logic implemented in Sharding/FullReplicationDBLogic.
	 */
	public abstract void processStatement();

	
	/**
	 * Forwards query to the corresponding connection.
	 * @param inString Query to be executed.
	 * @param connectionNumber Server number to send query to.
	 */
	protected void forwardQuery(String inString, int connectionNumber) {
		
		dbHandler.get(connectionNumber).executeQuery(inString);

	}
	
	/**
	 * Fetches the Result String of the current statement from the specified server connection.
	 * @param connectionNumber 
	 * @return
	 */
	protected String fetchResult(int connectionNumber) {
		return dbHandler.get(connectionNumber).getResultString();
	}
	
	/**
	 * Forwards an update statement to the specified server
	 * @param inString
	 * @param connectionNumber
	 */
	protected void forwardUpdate(String inString, int connectionNumber) {
		dbHandler.get(connectionNumber).executeUpdate(inString);
	}
	
	protected void forwardPreparedStatementStruct(String inString) {
		
		for (int i = 0; i < dbHandler.size(); i++) {
			dbHandler.get(i).setPreparedStatements(inString);			
		}
	}
	
	public void run() {
		
		while (true) {			
			if (!queue.isEmpty()) {
				processStatement();
			}
			
		}
	}
}
